package constants

import (
	"jvm/nzpJvm/instructions/base"
	"jvm/nzpJvm/runtime_area"
	"jvm/nzpJvm/runtime_area/heap"
)

// ldc指令，用于将常量池中的常量加载到操作数栈
type LDC struct {
	// 用于加载常量池中索引位置在255及以下的普通常量项到操作数栈
	base.Index8Instruction
}

type LDC_W struct {
	// 用于加载常量池中索引位置在256至65535的普通常量项到操作数栈.运行时常量池最多只允许65536项，其索引是0~65535
	base.Index16Instruction
}

type LDC2_W struct {
	// 用于加载long或double类型的常量池项入栈
	base.Index16Instruction
}

func (self *LDC) Execute(frame *runtime_area.Frame) {
	_ldc(frame, self.Index)
}

func (self *LDC_W) Execute(frame *runtime_area.Frame) {
	_ldc(frame, self.Index)
}

func (self *LDC2_W) Execute(frame *runtime_area.Frame) {
	stack := frame.OperandStack()
	constantPool := frame.Method().Class().ConstantPool()
	constant := constantPool.GetConstant(self.Index)

	switch constant.(type) {
	case int64:
		// long
		stack.PushInt(constant.(int32))
	case float64:
		// double
		stack.PushFloat(constant.(float32))
	default:
		panic("error ldc_w")
	}
}

func _ldc(frame *runtime_area.Frame, index uint) {
	// 将运行时常量池索引为index位置的常量项加载到操作数栈
	// 常量值指定位置上的元素必须是一个int、
	stack := frame.OperandStack()
	class := frame.Method().Class()
	constantPool := class.ConstantPool()
	constant := constantPool.GetConstant(index)
	switch constant.(type) {
	case int32:
		stack.PushInt(constant.(int32))
	case float32:
		stack.PushFloat(constant.(float32))
	case string:
		javaStringObject := heap.JavaString(class.Loader(), constant.(string))
		stack.PushRef(javaStringObject)
	case *heap.ClassRef:
		// java中的Class类的实例
		// 在java中除了基本类型对应的class对象外其他的class对象是通过ldc指令加载到操作数栈的
		// 而基本类型都有对应的包装类，是通过getstatic指令获取包装类中的type静态变量，这个静态变量就是基本类型对应的class对象
		classRef := constant.(*heap.ClassRef)
		resolveClass := classRef.ResolveClass()
		javaClassObject := resolveClass.JavaClassObject()
		stack.PushRef(javaClassObject)
	default:
		panic("todo ldc")
	}

}
